<template>
  <!-- 表格包装器，通过绑定高度来控制表格容器的大小 -->
  <div class="table-wrapper" :style="{ height: height + 'px' }">
    <!-- 可滚动的表格容器，用于容纳表格内容 -->
    <div class="scrollable-table-container" ref="scrollContainer">
      <!-- 样式化的表格 -->
      <table class="styled-table">
        <!-- 表头部分 -->
        <thead>
          <tr>
            <!-- 动态生成表头，每个表头都是根据columns数组中的元素创建 -->
            <th v-for="(item, index) in columns" :key="index">
              {{ item.title }}
            </th>
          </tr>
        </thead>
        <!-- 表体部分 -->
        <tbody ref="tableBody">
          <!-- 动态生成行，每行数据都基于displayData数组中的元素 -->
          <tr
            v-for="(item, index) in displayData"
            :key="`${item.uid}-${index}`"
            :class="{ 'even-row': index % 2 === 0 }"
            @click="handleRowClick(item)"
          >
            <!-- 生成列，根据columns数组循环创建 -->
            <td v-for="(v, colIndex) in columns" :key="colIndex">
              <!-- 根据表头名称显示不同的内容，对于特定的表头，如'预警状态'，应用特定的样式和文本 -->
              <template v-if="v.key === 'index'">{{ index + 1 }}</template>
              <template v-else-if="v.title === '预警状态'">
                <span :class="getStatusClass(item.status)">{{
                  getStatusText(item.status)
                }}</span>
              </template>
              <!-- 对于其他表头，直接显示对应的数据字段 -->
              <template v-else>
                {{ item[v.dataIndex] }}
              </template>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue";

const props = defineProps({
  columns: {
    type: Array,
    default: () => [],
  },
  // 表数据
  tableData: {
    type: Array,
    required: true,
    default: () => [],
  },
  // 表格高度
  height: {
    type: [Number, String],
    default: 300,
  },
});

const emit = defineEmits(["row-click"]); // 自定义事件

const scrollContainer = ref(null); // 滚动容器
const tableBody = ref(null); // 表格体
let scrollInterval = null; // 滚动间隔
let animationFrame = null; // 动画帧
let currentPosition = 0; // 当前滚动位置

// 配置参数
const config = {
  scrollSpeed: 0.5, // 滚动速度(像素/帧)
  cloneCount: 1, // 数据克隆次数
  rowHeight: 40, // 预估行高(像素)
};

// 为原始数据添加唯一标识
const processedData = computed(() => {
  return props.tableData.map((item, index) => ({
    ...item,
    uid: `row-${index}`,
  }));
});

// 创建显示数据（原始数据+克隆数据）
// 计算属性，用于生成包括原始数据和克隆数据在内的展示数据
const displayData = computed(() => {
  // 初始化一个空数组，用于存储克隆的数据
  const clonedData = [];

  // 根据config.cloneCount决定克隆的次数
  for (let i = 0; i < config.cloneCount; i++) {
    // 对原始数据进行克隆，并为每个克隆的数据项生成新的uid
    clonedData.push(
      ...processedData.value.map((item) => ({
        ...item,
        uid: `${item.uid}-clone-${i}`,
      }))
    );
  }

  // 返回展示数据，包括原始数据和所有克隆的数据
  return [...processedData.value, ...clonedData];
});

/**
 * 根据不同的状态返回相应的CSS类名
 * 该函数用于根据数据动态绑定CSS类，以实现页面元素的视觉差异化
 *
 * @param {String} status - 当前的状态，可以是'normal'、'approaching'或'overdue'
 * @returns {Object} 返回一个对象，包含不同状态下对应的CSS类名键值对
 */
const getStatusClass = (status) => ({
  "status-normal": status === "normal",
  "status-approaching": status === "approaching",
  "status-overdue": status === "overdue",
});

/**
 * 根据状态码获取对应的状态文本
 * @param {String} status 状态码，可以是 'normal', 'approaching', 'overdue' 中的一个
 * @returns {String} 对应的状态文本，如果状态码不存在则返回原始状态码
 */
const getStatusText = (status) =>
  ({
    normal: "正常",
    approaching: "临期",
    overdue: "逾期",
  }[status] || status);

// 行点击事件(暴露给父组件使用---用于跳转详情或者打开弹窗)
const handleRowClick = (item) => {
  emit("row-click", item);
};

/**
 * 平滑滚动函数
 * 该函数实现了一个平滑滚动的效果，通常用于改善用户体验
 */
const smoothScroll = () => {
  // 检查滚动容器是否存在，如果不存在则直接返回
  if (!scrollContainer.value) return;

  // 计算容器的高度
  const containerHeight = scrollContainer.value.clientHeight;
  // 计算内容的高度
  const contentHeight = tableBody.value.scrollHeight;
  // 计算最大滚动位置
  const maxScroll = contentHeight - containerHeight;

  // 根据配置的滚动速度更新当前滚动位置
  currentPosition += config.scrollSpeed;

  // 如果当前滚动位置达到或超过了最大滚动位置，则重置滚动位置
  if (currentPosition >= maxScroll) {
    currentPosition = 0;
    scrollContainer.value.scrollTop = 0;
  } else {
    // 请求下一动画帧，更新滚动位置
    animationFrame = requestAnimationFrame(() => {
      scrollContainer.value.scrollTop = currentPosition;
    });
  }
};

/**
 * 启动自动滚动功能
 *
 * 该函数用于启动一个自动滚动的动画效果，通过不断地调用平滑滚动函数来实现滚动效果
 * 它还设置了鼠标悬停和离开事件监听器，以便在鼠标悬停时停止滚动，在鼠标离开时恢复滚动
 */
const startAutoScroll = () => {
  let isScrolling = true;

  // 使用setInterval以约60fps的频率不断调用平滑滚动函数，实现自动滚动效果
  scrollInterval = setInterval(() => {
    if (isScrolling) smoothScroll();
  }, 16); // 约60fps

  // 当鼠标悬停在滚动容器上时，停止自动滚动
  scrollContainer.value.addEventListener(
    "mouseenter",
    () => (isScrolling = false)
  );
  // 当鼠标从滚动容器上移开时，恢复自动滚动
  scrollContainer.value.addEventListener(
    "mouseleave",
    () => (isScrolling = true)
  );
};

onMounted(() => {
  startAutoScroll();
});

onBeforeUnmount(() => {
  clearInterval(scrollInterval);
  cancelAnimationFrame(animationFrame);
});
</script>

<style lang="scss" scoped>
.table-wrapper {
  position: relative;
  overflow: hidden;
}

.scrollable-table-container {
  height: 100%;
  overflow-y: auto;
  position: relative;
  scrollbar-width: none;

  &::-webkit-scrollbar {
    display: none;
  }
}

.styled-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;

  thead {
    position: sticky;
    top: 0;
    z-index: 10;
    background-color: rgba(3, 129, 244, 0.3);
    th {
      // background: rgba(8, 21, 41, 1);
      // background: linear-gradient(0deg, #18539f 0.01%, #142646 96.77%);
      // box-shadow: 0 2px 8px 0 #3457dc29;
      color: #fff;
      font-size: 14px;
      font-weight: 600;
      text-align: center;
      padding: 12px 15px;
      border: none;
      position: sticky;
      top: 0;
      // border-bottom: 1px solid #f0f0f0;

      &:not(:last-child) {
        &::before {
          position: absolute;
          top: 50%;
          inset-inline-end: 0;
          width: 1px;
          height: 1.6em;
          // background-color: #f0f0f0;
          transform: translateY(-50%);
          transition: background-color 0.2s;
          content: "";
        }
      }
    }
  }

  tbody {
    tr {
      color: #fff;
      font-family: "PingFang SC";
      font-size: 12px;
      font-weight: 400;
      text-align: center;
      transition: transform 0.2s ease-out;
      cursor: pointer;

      &:hover {
        background: rgba(75, 130, 225, 0.3) !important;
      }

      td {
        font-size: 14px;
        padding: 12px 8px;
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
      }

      // 奇数行 - 浅蓝背景
      &:nth-child(odd) {
        background: #05335e00;
      }

      // 偶数行 - 透明背景
      &:nth-child(even) {
        background: #4b82e11a;
      }
    }
  }
}

.status-normal {
  color: #409eff;
}

.status-approaching {
  color: #e6a23c;
}

.status-overdue {
  color: #f56c6c;
}
</style>
